home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 1 / ETO Development Tools 1.iso / Tools - Objects / MacApp / MacApp 2.0 CD Release / MacApp 2.0 (Many Libraries) / Libraries / UMenuSetup.inc1.p < prev    next >
Encoding:
Text File  |  1990-03-27  |  20.1 KB  |  786 lines  |  [TEXT/MPS ]

  1. {$P}
  2. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  3. { UMenuSetup.inc1.p }
  4. { Copyright © 1984-1990 by Apple Computer Inc. All rights reserved. }
  5.  
  6. {--------------------------------------------------------------------------------------------------}
  7.  
  8. CONST
  9.     _MAInvalMenuBar = $A81D;            { Trap number for invalidate menu bar on 7.0 systems }
  10.  
  11. TYPE
  12.     { the following must match the declaration in the PostRez tool }
  13.     MenuCmdRecord        = RECORD
  14.         theCmdNumber:        INTEGER;
  15.         theMenuNumber:        INTEGER;
  16.         theItemNumber:        INTEGER;
  17.         END;
  18.  
  19.     CmdTable            = ARRAY [1..4000] OF MenuCmdRecord; { Actually variable length }
  20.     CmdTablePtr         = ^CmdTable;
  21.     CmdTableHandle        = ^CmdTablePtr;
  22.  
  23.     MAMenuCRsrcPtr        = ^MAMenuCRsrc;                    {!!! After MPW 3.1 use the PInterfaces vers }
  24.     MAMenuCRsrcHandle    = ^MAMenuCRsrcPtr;
  25.     MAMenuCRsrc         = RECORD
  26.         numEntries:         INTEGER;                    {number of entries}
  27.         data:                ARRAY [1..1] OF MCEntry;
  28.         END;
  29.  
  30. PROCEDURE MAInvalMenuBar;
  31. INLINE _MAInvalMenuBar;
  32. { The trap name will be InvalMenuBar. The trap number will be $A81D. It will
  33. test as unimplemented on old systems. (There will also be a Gestalt selector.) }
  34.  
  35. {--------------------------------------------------------------------------------------------------}
  36.  
  37. VAR
  38.     pHNullMenuProc:     Handle;                         { Handle to null menu proc }
  39.  
  40.     pCmdTable:            CmdTableHandle;                 { maps CmdNumber <--> (menu,item) }
  41.     pSizeCmdTable:        INTEGER;                        { number of records in pCmdTable }
  42.  
  43. {--------------------------------------------------------------------------------------------------}
  44.  
  45. PROCEDURE NullMenuProc(message: INTEGER;
  46.                        aMenuHandle: MenuHandle;
  47.                        VAR menuRect: Rect;
  48.                        hitPt: Point;
  49.                        VAR whichItem: INTEGER);
  50.     FORWARD;
  51.  
  52. {--------------------------------------------------------------------------------------------------}
  53. {$IFC qDebug}
  54. {$S MADebug}
  55.  
  56. FUNCTION TraceMenuName(aCmd: CmdNumber): CHAR;
  57. { For debugging purposes only--used to dump the name and number of a command }
  58.  
  59.     VAR
  60.         cmdName:            Str255;
  61.  
  62.     BEGIN
  63.     CmdToName(aCmd, cmdName);
  64.     Write(aCmd: 1, ' [', cmdName, '],');
  65.     TraceMenuName := ' ';
  66.     END;
  67. {$ENDC}
  68.  
  69. {--------------------------------------------------------------------------------------------------}
  70. {$S MAMenuRes}
  71.  
  72. PROCEDURE InvalidateMenus;
  73.  
  74.     BEGIN
  75.     gMenusAreSetup := FALSE;
  76.     END;
  77.  
  78. {--------------------------------------------------------------------------------------------------}
  79. {$S MAMenuRes}
  80.  
  81. PROCEDURE ValidateMenus;
  82.  
  83.     BEGIN
  84.     gMenusAreSetup := TRUE;
  85.     END;
  86.  
  87. {--------------------------------------------------------------------------------------------------}
  88. {$S MAMenuRes}
  89.  
  90. FUNCTION MenusHavePendingUpdate: Boolean;
  91.  
  92.     BEGIN
  93.     MenusHavePendingUpdate := NOT gMenusAreSetup;
  94.     END;
  95.  
  96. {--------------------------------------------------------------------------------------------------}
  97. {$S MAMenuRes}
  98.  
  99. PROCEDURE InvalidateMenuBar;
  100.  
  101.     BEGIN
  102.     InvalidateMenus;                                    { if the menubar is invalidated then the
  103.                                                          menu items must be also }
  104.  
  105.  
  106.     { On systems that have invalidate menu bar use that functionality instead of setting the global.
  107.     The system will redraw the menu bar at the next convenient time. }
  108.     IF TrapExists(_MAInvalMenuBar) THEN
  109.         BEGIN
  110.         MAInvalMenuBar;
  111.         gRedrawMenuBar := FALSE;
  112.         END
  113.     ELSE
  114.         gRedrawMenuBar := TRUE;
  115.     END;
  116.  
  117. {--------------------------------------------------------------------------------------------------}
  118. {$S MAMenuRes}
  119.  
  120. PROCEDURE ValidateMenuBar;
  121.  
  122.     BEGIN
  123.     gRedrawMenuBar := FALSE;
  124.     END;
  125.  
  126. {--------------------------------------------------------------------------------------------------}
  127. {$S MAMenuRes}
  128.  
  129. FUNCTION MenuBarHasPendingUpdate;
  130.  
  131.     BEGIN
  132.     MenuBarHasPendingUpdate := gRedrawMenuBar;
  133.     END;
  134.  
  135. {--------------------------------------------------------------------------------------------------}
  136. {$S MAMenuRes}
  137.  
  138. FUNCTION CmdEnabled(cmd: CmdNumber): Boolean;
  139.  
  140.     VAR
  141.         menuNo, itemNo:     INTEGER;
  142.         theMenu:            MenuHandle;
  143.  
  144.     BEGIN
  145.     theMenu := CmdToComponents(cmd, menuNo, itemNo);
  146.  
  147.     IF theMenu <> NIL THEN
  148.         IF (itemNo > 0) & (itemNo < 32) THEN
  149.             CmdEnabled := BTst(theMenu^^.enableFlags, itemNo)
  150.         ELSE
  151.             CmdEnabled := TRUE
  152.     ELSE
  153.         CmdEnabled := FALSE;
  154.     END;
  155.  
  156. {--------------------------------------------------------------------------------------------------}
  157. {$S MAMenuRes}
  158.  
  159. FUNCTION CmdFromMenuItem(menu, item: INTEGER): CmdNumber;
  160.  { Given a menuID/item # return the appropriate command number. IF there
  161.   is no such command number, return -BOR(BSL(menu, 8), item).  If the
  162.   item number is <0 then assume that it is a negative command number. }
  163.  
  164.     VAR
  165.         i:                    INTEGER;
  166.         p:                    CmdTablePtr;
  167.  
  168.     BEGIN
  169.     IF item < 0 THEN
  170.         CmdFromMenuItem := - item
  171.     ELSE
  172.         BEGIN
  173.         IF item > 0 THEN
  174.             BEGIN
  175.             p := pCmdTable^;
  176.  
  177.             FOR i := 1 TO pSizeCmdTable DO
  178.                 WITH p^[i] DO
  179.                     IF (menu = theMenuNumber) & (item = theItemNumber) THEN
  180.                         BEGIN
  181.                         CmdFromMenuItem := theCmdNumber;
  182.                         Exit(CmdFromMenuItem);
  183.                         END;
  184.             END;
  185.         {$IFC qDebug}
  186.         IF (menu > 127) | (item > 255) THEN
  187.             BEGIN
  188.             Writeln('menu = ', menu: 1, '  item = ', item: 1);
  189.             Writeln('Menu/item number is too big for a negative command number!');
  190.             ProgramBreak('Try using a negative item number instead.');
  191.             END;
  192.         {$ENDC}
  193.  
  194.         CmdFromMenuItem := - BOR(BSL(menu, 8), item);
  195.         END;
  196.     END;
  197.  
  198. {--------------------------------------------------------------------------------------------------}
  199. {$S MAMenuRes}
  200.  
  201. PROCEDURE CmdToMenuItem(aCmd: CmdNumber;
  202.                         VAR menu, item: INTEGER);
  203.  
  204.     VAR
  205.         p:                    CmdTablePtr;
  206.         low:                INTEGER;
  207.         high:                INTEGER;
  208.         test:                INTEGER;
  209.  
  210.     BEGIN
  211.     IF aCmd < 0 THEN
  212.         BEGIN
  213.         menu := BSR( - aCmd, 8);
  214.         item := BAND( - aCmd, 255);
  215.         END
  216.     ELSE
  217.         BEGIN
  218.         { Use a binary search to find the command number in the table }
  219.         low := 1;
  220.         high := pSizeCmdTable;
  221.  
  222.         p := pCmdTable^;
  223.         WHILE low <= high DO
  224.             BEGIN
  225.             test := BSR(low + high, 1);                 { (low + high) DIV 2 }
  226.             WITH p^[test] DO
  227.                 IF aCmd = theCmdNumber THEN
  228.                     BEGIN
  229.                     menu := theMenuNumber;
  230.                     item := theItemNumber;
  231.                     Exit(CmdToMenuItem);
  232.                     END
  233.                 ELSE IF aCmd < theCmdNumber THEN
  234.                     high := test - 1
  235.                 ELSE
  236.                     low := test + 1;
  237.             END;
  238.  
  239.         { not found }
  240.         menu := 0;
  241.         item := 0;
  242.         END;
  243.     END;
  244.  
  245. {--------------------------------------------------------------------------------------------------}
  246. {$S MAMenuRes}
  247.  
  248. PROCEDURE CmdToName(aCmd: CmdNumber;
  249.                     VAR menuText: Str255);
  250.  
  251.     VAR
  252.         aMenu:                INTEGER;
  253.         anItem:             INTEGER;
  254.         mHandle:            MenuHandle;
  255.  
  256.     BEGIN
  257.     menuText := '';
  258.  
  259.     mHandle := CmdToComponents(aCmd, aMenu, anItem);
  260.     IF mHandle <> NIL THEN
  261.         GetItem(mHandle, anItem, menuText);
  262.     END;
  263.  
  264. {--------------------------------------------------------------------------------------------------}
  265. {$S MAMenuRes}
  266.  
  267. FUNCTION CmdToComponents(cmd: CmdNumber; VAR menuNo, itemNo: integer): MenuHandle;
  268.  
  269.     VAR
  270.         theMenu: MenuHandle;
  271.  
  272.     BEGIN
  273.     CmdToMenuItem(cmd, menuNo, itemNo);
  274.     IF menuNo <> 0 THEN { was found }
  275.         CmdToComponents := MAGetMenu(menuNo)
  276.     ELSE
  277.         CmdToComponents := NIL;
  278.     END;
  279.  
  280. {--------------------------------------------------------------------------------------------------}
  281. {$S MAMenuRes}
  282.  
  283. PROCEDURE EachMenuDo(PROCEDURE DoToMenu(aMenuHandle: MenuHandle; isHierarchical: Boolean);
  284.                      includeHierarchical: Boolean);
  285.  { Calls DoToMenu for each menu in the menu bar, including the
  286.   hierarchical and popup menus if includeHierarchical is TRUE. }
  287.     CONST
  288.         kHierArchical        = TRUE;
  289.         kNotHierArchical    = NOT kHierArchical;
  290.  
  291.     TYPE
  292.         { See IM V, Menu Manager, 'Menu Mgr Data Structures' pp.228-30 }
  293.         MAMenuRec            = RECORD
  294.             menuOH:             MenuHandle;             { menu's data }
  295.             menuLeft:            INTEGER;                { pixels }
  296.             END;
  297.         MAMenuRecPtr        = ^MAMenuRec;
  298.  
  299.         MAHMenuRec            = RECORD
  300.             menuOH:             MenuHandle;             { hierarchical menu's data }
  301.             reserved:            INTEGER;                { reserved for future use }
  302.             END;
  303.         MAHMenuRecPtr        = ^MAHMenuRec;
  304.  
  305.         MADynamicMenuList    = RECORD
  306.             lastMenu:            INTEGER;                { Offset }
  307.             lastRight:            INTEGER;                { Pixels }
  308.             mbResID:            INTEGER;
  309.             menu:                ARRAY [0..0] OF MAMenuRec; { Variable number of menus }
  310.  
  311.             lastHMenu:            INTEGER;                { Offset }
  312.             menuTitleSave:        PixMapHandle;            { handle to bits behind inverted menu title
  313.                                                          }
  314.             hMenu:                 ARRAY [0..0] OF MAHMenuRec; { Variable number of menus }
  315.             END;
  316.         MADynamicMenuListPtr = ^MADynamicMenuList;
  317.         MADynamicMenuListHandle = ^MADynamicMenuListPtr;
  318.  
  319.     PROCEDURE WalkAMenuRecArray(aMenuRecPtr: MAMenuRecPtr;
  320.                                 lastMenuOffset: INTEGER;
  321.                                 isHierarchical: Boolean);
  322.     { NOTE: Assumes a MAMenuRec and a MAHMenuRec are the same size }
  323.  
  324.         VAR
  325.             aMenuHandle:        MenuHandle;
  326.             endAddress:            MAMenuRecPtr;
  327.  
  328.         BEGIN
  329.         endAddress := MAMenuRecPtr(ORD(aMenuRecPtr) + lastMenuOffset);
  330.         While (ORD(aMenuRecPtr) < ORD(endAddress)) DO
  331.             BEGIN
  332.             aMenuHandle := aMenuRecPtr^.menuOH;
  333.  
  334.             IF qDebug & NOT IsHandle(aMenuHandle) THEN
  335.                 BEGIN
  336.                 IF VerboseIsHandle(aMenuHandle) THEN;
  337.                 WrLblPtr('Bad menuHandle was', aMenuHandle);
  338.                 ProgramBreak('I guess it''s not a MenuHandle, huh?');
  339.                 END
  340.             ELSE
  341.                 FailNIL(aMenuHandle);
  342.  
  343.             IF (qDebug | qInspector) & (aMenuHandle^^.menuID = mDebug) THEN {??? why? }
  344.                 BEGIN
  345.                 aMenuHandle^^.menuID := 0;                { store info about debug menu in index 0 }
  346.                 DoToMenu(aMenuHandle, isHierarchical);
  347.                 aMenuHandle^^.menuID := mDebug;
  348.                 END
  349.             ELSE
  350.             DoToMenu(aMenuHandle, isHierarchical);
  351.  
  352.             aMenuRecPtr := MAMenuRecPtr(ORD(aMenuRecPtr) + SizeOf(MAMenuRec));
  353.             END;
  354.         END;
  355.  
  356.     BEGIN
  357.     { Do regular menus }
  358.     WITH MADynamicMenuListHandle(GetMenuList)^^ DO
  359.         WalkAMenuRecArray(MAMenuRecPtr(@menu), lastMenu, kNotHierArchical);
  360.  
  361.     { Now do hierarchial menus }
  362.     IF (qNeedsHierarchicalMenus | gConfiguration.hasHierarchicalMenus) & includeHierarchical THEN
  363.         WITH MADynamicMenuListHandle(GetMenuList)^^ DO
  364.             WalkAMenuRecArray(MAMenuRecPtr(ORD(@menu) + lastMenu + SizeOf(INTEGER) +
  365.                                            SizeOf(PixMapHandle)), IntegerPtr(ORD(@menu) +
  366.                               lastMenu)^, kHierArchical);
  367.     END;
  368.  
  369. {--------------------------------------------------------------------------------------------------}
  370. {$S MAMenuRes}
  371.  
  372. PROCEDURE Enable(aCmd: CmdNumber;
  373.                  canDo: Boolean);
  374.  
  375.     VAR
  376.         menu, item:         INTEGER;
  377.         aMenuHandle:        MenuHandle;
  378.  
  379.     BEGIN
  380.     {$IFC qDebug}
  381.     IF gTraceSetupMenus THEN
  382.         Writeln('..... Enable(', TraceMenuName(aCmd), gBoolString[canDo], ')');
  383.     {$ENDC}
  384.     aMenuHandle := CmdToComponents(aCmd, menu, item);
  385.     IF aMenuHandle <> NIL THEN
  386.         IF canDo THEN
  387.             EnableItem(aMenuHandle, item)
  388.         ELSE
  389.             DisableItem(aMenuHandle, item);
  390.     END;
  391.  
  392. {--------------------------------------------------------------------------------------------------}
  393. {$S MAMenuRes}
  394.  
  395. PROCEDURE EnableCheck(aCmd: CmdNumber;
  396.                       canDo, checkIt: Boolean);
  397.  
  398.     VAR
  399.         menu, item:         INTEGER;
  400.         aMenuHandle:        MenuHandle;
  401.  
  402.     BEGIN
  403.     {$IFC qDebug}
  404.     IF gTraceSetupMenus THEN
  405.         Writeln('..... EnableCheck(', TraceMenuName(aCmd), gBoolString[canDo], ', ',
  406.                 gBoolString[checkIt], ')');
  407.     {$ENDC}
  408.     aMenuHandle := CmdToComponents(aCmd, menu, item);
  409.     IF aMenuHandle <> NIL THEN
  410.         BEGIN
  411.         IF canDo THEN
  412.             EnableItem(aMenuHandle, item)
  413.         ELSE
  414.             DisableItem(aMenuHandle, item);
  415.         CheckItem(aMenuHandle, item, checkIt);
  416.         END;
  417.     END;
  418.  
  419. {--------------------------------------------------------------------------------------------------}
  420. {$S MAMenuRes}
  421.  
  422. FUNCTION GetResMenu(menuResID: INTEGER): MenuHandle;
  423. { Allow us to get a menu when it's not available via GetMHandle. 
  424. !!! Really should perform the other functions of GetMenu (load menuproc, color table, etc.}
  425.  
  426.     PROCEDURE DoGetResMenu;
  427.  
  428.         BEGIN
  429.         GetResMenu := MenuHandle(GetResource('MENU', menuResID));
  430.         END;
  431.  
  432.     BEGIN
  433.     WithApplicationResFileDo(DoGetResMenu);
  434.     END;
  435.  
  436. {--------------------------------------------------------------------------------------------------}
  437. {$S MAInit}
  438.  
  439. PROCEDURE InitUMenuSetup;
  440.  
  441.     TYPE
  442.         JmpRecPtr            = ^JmpRec;
  443.         JmpRec                = RECORD
  444.             opcode:             INTEGER;
  445.             target:             Ptr;
  446.             END;
  447.  
  448.         {$IFC qDebug}
  449.  
  450.     VAR
  451.         i:                    INTEGER;
  452.         previousCmdNumber:    INTEGER;
  453.         {$ENDC}
  454.  
  455.     BEGIN
  456.     { read in the command table }
  457.     pCmdTable := CmdTableHandle(GetResource(kMNTBbyCmdNumber, kIDMNTBbyCmdNumber));
  458.     FailNilResource(pCmdTable);
  459.     pSizeCmdTable := GetHandleSize(Handle(pCmdTable)) DIV SIZEOF(MenuCmdRecord);
  460.  
  461.     {$IFC qDebug}
  462.     previousCmdNumber := MAXINT;
  463.     FOR i := 1 TO pSizeCmdTable DO
  464.         BEGIN
  465.         IF pCmdTable^^[i].theCmdNumber = previousCmdNumber THEN
  466.             ProgramBreak(ConcatNumber('Duplicate command number not allowed: ', previousCmdNumber));
  467.         previousCmdNumber := pCmdTable^^[i].theCmdNumber;
  468.         END;
  469.     {$ENDC}
  470.  
  471.     pHNullMenuProc := NewPermHandle(6);
  472.     FailNIL(pHNullMenuProc);
  473.     WITH JmpRecPtr(pHNullMenuProc^)^ DO
  474.         BEGIN
  475.         opcode := $4EF9;                                { JMP }
  476.         target := @NullMenuProc;
  477.         END;
  478.  
  479.     InvalidateMenuBar;
  480.     END;
  481.  
  482. {--------------------------------------------------------------------------------------------------}
  483. {$S MAMenuRes}
  484.  
  485. FUNCTION MAGetMenu(menuNo: INTEGER): MenuHandle;
  486.  
  487.     VAR
  488.         theMenu: MenuHandle;
  489.  
  490.     BEGIN
  491.     theMenu := GetMHandle(menuNo); { do this first ... the menu is likely to be in the menubar and
  492.                                     more likely of success, hence, faster }
  493.     IF theMenu = NIL THEN
  494.         theMenu := GetResMenu(menuNo);
  495.  
  496.     MAGetMenu := theMenu;
  497.     END;
  498.  
  499.  
  500. {--------------------------------------------------------------------------------------------------}
  501. {$S MAInit}
  502.  
  503. FUNCTION MAGetNewMBar(menuRsrcID: INTEGER): Handle;
  504.  
  505.     VAR
  506.         theColorTab:        MCTableHandle;
  507.         theColorRsrc:        MAMenuCRsrcHandle;
  508.  
  509.     BEGIN
  510.     IF qNeedsColorQD | gConfiguration.hasColorQD THEN
  511.         theColorTab := GetMCInfo;
  512.     MAGetNewMBar := GetNewMBar(menuRsrcID);
  513.     IF (theColorTab <> NIL) THEN
  514.         IF qNeedsColorQD | gConfiguration.hasColorQD THEN
  515.             BEGIN
  516.             HLock(Handle(theColorTab));
  517.             SetMCEntries(GetHandleSize(Handle(theColorTab)) DIV SIZEOF(MCEntry), theColorTab^);
  518.             HUnlock(Handle(theColorTab));
  519.             DispMCInfo(theColorTab);
  520.             END;
  521.     END;
  522.  
  523. {--------------------------------------------------------------------------------------------------}
  524. {$S MAMenuRes}
  525.  
  526. PROCEDURE MAInsertMenu(theMenu: MenuHandle;
  527.                        beforeID: INTEGER);
  528.  
  529.     VAR
  530.         theColorRsrc:        MAMenuCRsrcHandle;
  531.  
  532.     BEGIN
  533.     InsertMenu(theMenu, beforeID);
  534.  { Since only GetMenu automatically loads the appropriate color information,
  535.   and (sigh) since we can only call GetMenu once, and if you call DeleteMenu
  536.   all the good color stuff goes away (double sigh) we'll have to help out
  537.   the Menu Manager by doing its job for it }
  538.     IF qNeedsColorQD | gConfiguration.hasColorQD THEN
  539.         BEGIN
  540.         theColorRsrc := MAMenuCRsrcHandle(GetResource('mctb', theMenu^^.menuID));
  541.         IF theColorRsrc <> NIL THEN
  542.             BEGIN
  543.             HLock(Handle(theColorRsrc));
  544.             WITH theColorRsrc^^ DO
  545.                 SetMCEntries(numEntries, @data[1]);
  546.             HUnlock(Handle(theColorRsrc));
  547.             ReleaseResource(Handle(theColorRsrc));
  548.             END;
  549.         END;
  550.     END;
  551.  
  552. {--------------------------------------------------------------------------------------------------}
  553. {$S MAMenuRes}
  554.  
  555. PROCEDURE NeedCalcMenuSize(aMenuHandle: MenuHandle);
  556.  
  557.     BEGIN
  558.     WITH aMenuHandle^^ DO
  559.         IF menuProc = pHNullMenuProc THEN
  560.             menuWidth := 0;
  561.     END;
  562.  
  563. {--------------------------------------------------------------------------------------------------}
  564. {$S MAMenuRes}
  565.  { a null menuProc that is used to inhibit re-calculating the menu's size after each
  566.   call to EnableItem, CheckItem, etc. }
  567.  
  568. PROCEDURE NullMenuProc(message: INTEGER;
  569.                        aMenuHandle: MenuHandle;
  570.                        VAR menuRect: Rect;
  571.                        hitPt: Point;
  572.                        VAR whichItem: INTEGER);
  573.  
  574.     BEGIN
  575.     aMenuHandle^^.menuWidth := 0;
  576.     END;
  577.  
  578. {--------------------------------------------------------------------------------------------------}
  579. {$S MAMenuRes}
  580.  
  581. PROCEDURE PerformMenuSetup(PROCEDURE TheMenuSetterUpper);
  582.  
  583.     CONST
  584.         kDoHierArchical        = TRUE;
  585.         kDontDoHierArchical    = NOT kDoHierArchical;
  586.  
  587.         { If hierarchical the range of IDs for applications is restricted
  588.         See IM V-236. }
  589.         kHierarchicalMin    = 0;
  590.         kHierarchicalMax    = 235;
  591.  
  592.  
  593.     TYPE
  594.         EnableArray         = PACKED ARRAY [0..mLastMenu] OF Boolean; { Saved enable flags }
  595.         SavePrArray         = ARRAY [0..mLastMenu] OF Handle; { Saved menu procs }
  596.  
  597.     VAR
  598.         aMenuHandle:        MenuHandle;
  599.         wasEnabled:         EnableArray;
  600.         savedProcs:         SavePrArray;
  601.  
  602. FUNCTION IsManagedMenu(aMenuHandle: MenuHandle; isHierarchical: Boolean): BOOLEAN;
  603.  
  604.     BEGIN
  605.     WITH aMenuHandle^^ DO
  606.     IsManagedMenu := (((menuID >= mFirstMenu) & (menuID <= mLastMenu)) { Range of managed menus }
  607.            & (menuID <> mApple)                                        { _NEVER_ managed! }
  608.            & (NOT isHierarchical                                    { No further restrictions, unless… }
  609.            | (isHierarchical & (menuID >= kHierarchicalMin) & (menuID <= kHierarchicalMax)))) { must
  610.                be in valid range }
  611.     END;
  612.  
  613. PROCEDURE StartMenuSetup(aMenuHandle: MenuHandle; isHierarchical: Boolean);
  614.  
  615.     VAR
  616.         item: INTEGER;
  617.         theCmd: CHAR;
  618.  
  619.     BEGIN
  620.     IF IsManagedMenu(aMenuHandle, isHierarchical) THEN
  621.         WITH aMenuHandle^^ DO
  622.             BEGIN
  623.                 { Remember the menu itself was enabled, and disable the menu
  624.                  and all of its items. }
  625.             wasEnabled[menuID] := Odd(enableFlags);
  626.             enableFlags := 0;
  627.  
  628.                 { Save the menu's menuproc and set it to the NullMenuProc, so that
  629.                  CalcMenuSize is disabled (will do ÇalcMenuSize at end of setup). }
  630.             savedProcs[menuID] := menuProc; { See comment below }
  631.             menuProc := pHNullMenuProc;
  632.  
  633.             { Uncheck all items. }
  634.             FOR item := 1 TO CountMItems(aMenuHandle) DO
  635.               { Make sure we don't check items with sub-menus }
  636.                 IF qNeedsHierarchicalMenus | gConfiguration.hasHierarchicalMenus THEN
  637.                     BEGIN
  638.                     GetItemCmd(aMenuHandle, item, theCmd);
  639.                     IF ORD(theCmd) <> hMenuCmd THEN
  640.                         CheckItem(aMenuHandle, item, FALSE);
  641.                     END
  642.                 ELSE
  643.                     CheckItem(aMenuHandle, item, FALSE);
  644.             END;
  645.     END;
  646.  
  647. PROCEDURE EndMenuSetup(aMenuHandle: MenuHandle; isHierarchical: Boolean);
  648.  
  649.     VAR
  650.         newFlags: LongInt;
  651.         menuID: INTEGER;
  652.  
  653.     BEGIN
  654.     IF IsManagedMenu(aMenuHandle, isHierarchical) THEN
  655.         WITH aMenuHandle^^ DO
  656.             BEGIN
  657.  
  658.             newFlags := enableFlags;
  659.             { If any items are enabled, enable the menu }
  660.             IF newFlags <> 0 THEN
  661.                 BEGIN
  662.                 newFlags := BOR(1, newFlags);
  663.                 enableFlags := newFlags;
  664.                 END;
  665.  
  666.             { If the menu's enabled state changed, we have to draw the menu bar. }
  667.             IF Odd(newFlags) <> wasEnabled[menuID] THEN
  668.                 InvalidateMenuBar;
  669.  
  670.             { Restore the menuproc. }
  671.             menuProc := savedProcs[menuID];
  672.  
  673.                 { menuWidth set to 0 by routines that require CalcMenuSize, by
  674.                  calling NeedCalcMenu. }
  675.             IF menuWidth = 0 THEN
  676.                 CalcMenuSize(aMenuHandle);
  677.             END;
  678.     END;
  679.  
  680.     BEGIN
  681.     EachMenuDo(StartMenuSetup, kDoHierArchical);
  682.     TheMenuSetterUpper;
  683.     EachMenuDo(EndMenuSetup, kDoHierArchical);
  684.  
  685.     IF MenuBarHasPendingUpdate THEN
  686.         BEGIN
  687.         DrawMenuBar;
  688.         ValidateMenuBar;
  689.         END;
  690.  
  691.     ValidateMenus;
  692.     END;
  693.  
  694. {--------------------------------------------------------------------------------------------------}
  695. {$S MAMenuRes}
  696.  
  697. PROCEDURE SetCmdIcon(aCmd: CmdNumber;
  698.                      menuIcon: Byte);
  699.  
  700.     VAR
  701.         menu, item:         INTEGER;
  702.         aMenuHandle:        MenuHandle;
  703.  
  704.     BEGIN
  705.     {$IFC qDebug}
  706.     IF gTraceSetupMenus THEN
  707.         Writeln('..... SetCmdIcon(', TraceMenuName(aCmd), menuIcon: 1, ')');
  708.     {$ENDC}
  709.     aMenuHandle := CmdToComponents(aCmd, menu, item);
  710.     IF aMenuHandle <> NIL THEN
  711.         SetItemIcon(aMenuHandle, item, menuIcon);
  712.     END;
  713.  
  714. {--------------------------------------------------------------------------------------------------}
  715. {$S MAMenuRes}
  716.  
  717. PROCEDURE SetCmdName(aCmd: CmdNumber;
  718.                      menuText: Str255);
  719.  
  720.     VAR
  721.         menu, item:         INTEGER;
  722.         aMenuHandle:        MenuHandle;
  723.  
  724.     BEGIN
  725.     {$IFC qDebug}
  726.     IF gTraceSetupMenus THEN
  727.         Writeln('..... SetCmdName(', TraceMenuName(aCmd), '“', menuText, '”)');
  728.     {$ENDC}
  729.     aMenuHandle := CmdToComponents(aCmd, menu, item);
  730.     IF aMenuHandle <> NIL THEN
  731.         SetItem(aMenuHandle, item, menuText);
  732.     END;
  733.  
  734. {--------------------------------------------------------------------------------------------------}
  735. {$S MAMenuRes}
  736.  
  737. PROCEDURE SetIndCmdName(aCmd: CmdNumber;
  738.                         rsrcID, strIndex: INTEGER);
  739.  
  740.     VAR
  741.         s:                    Str255;
  742.  
  743.     BEGIN
  744.     GetIndString(s, rsrcID, strIndex);
  745.     SetCmdName(aCmd, s);
  746.     END;
  747.  
  748. {--------------------------------------------------------------------------------------------------}
  749. {$S MAMenuRes}
  750.  
  751. PROCEDURE SetMenuState(aCmd: CmdNumber;
  752.                        rsrcID, falseBuzzItem, trueBuzzItem: INTEGER;
  753.                        stateVariable: Boolean);
  754.  
  755.     VAR
  756.         buzzItem:            INTEGER;
  757.  
  758.     BEGIN
  759.     IF stateVariable THEN
  760.         buzzItem := trueBuzzItem
  761.     ELSE
  762.         buzzItem := falseBuzzItem;
  763.  
  764.     SetIndCmdName(aCmd, rsrcID, buzzItem);
  765.     END;
  766.  
  767. {--------------------------------------------------------------------------------------------------}
  768. {$S MAMenuRes}
  769.  
  770. PROCEDURE SetStyle(aCmd: CmdNumber;
  771.                    aStyle: Style);
  772.  
  773.     VAR
  774.         menu, item:         INTEGER;
  775.         aMenuHandle:        MenuHandle;
  776.  
  777.     BEGIN
  778.     {$IFC qDebug}
  779.     IF gTraceSetupMenus THEN
  780.         Writeln('..... SetStyle(', TraceMenuName(aCmd), Ptr(@aStyle)^: 1, ')');
  781.     {$ENDC}
  782.     aMenuHandle := CmdToComponents(aCmd, menu, item);
  783.     IF aMenuHandle <> NIL THEN
  784.         SetItemStyle(aMenuHandle, item, aStyle);
  785.     END;
  786.